home *** CD-ROM | disk | FTP | other *** search
/ Complete Linux / Complete Linux.iso / docs / apps / tex / lametex_.z / lametex_ / lametex / src / FileInput.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-09-19  |  20.3 KB  |  731 lines

  1. /* FileInput.C
  2.  *
  3.  * FileInput holds a series of routines to fetch tokens or free text from
  4.  * the user LaTeX input.
  5.  *
  6.  * Copyright 1992 Jonathan Monsarrat. Permission given to freely distribute,
  7.  * edit and use as long as this copyright statement remains intact.
  8.  *
  9.  */
  10.  
  11. #include <ctype.h>
  12. #include <string.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15. #include <sys/types.h>
  16. #include <sys/stat.h>
  17. #include "Global.h"
  18. #include "Document.h"
  19. #include "Font.h"
  20. #include "Operator.h"
  21.  
  22. static int comma_delimiter_valid = 0;
  23. static int parsing_length = FALSE;
  24. static int parsing_command = FALSE;
  25.  
  26. static void usage()
  27. {
  28.    cout << "Usage: lametex [-p psfile] [-d psdir] [ -t ] texfile" << endl;
  29.    cout
  30.       << "Use -p psfile to specify the name of the default LameTeX page to use."
  31.       << endl;
  32.    cout << "Use -d psdir to specify an additional directory in which" << endl;
  33.    cout << "  to search for LameTeX page definitions." << endl;
  34.    cout << "Use -t to specify that LameTeX should produce a plain text output"
  35.         << endl;
  36. }
  37.  
  38. FileInput::FileInput(int argc, char *argv[])
  39. {
  40.    filename[0] = '\0';
  41.    pspage[0] = '\0';
  42.    current_pspage[0] = '\0';
  43.    blankline_area = 1;  // Suppress any new paragraphs
  44.    newline_in_this_blankline_area = 0;
  45.    vspace_in_this_blankline_area = 0.0;
  46.    readjust_vspace = 0.0;
  47.    plain_text_output = 0;
  48.  
  49.    // Make an array of directories to look in for LameTeX page descriptions
  50.    num_pagedirs = 0;
  51.    add_pagedir("./");      // current directory
  52.    add_pagedir(PAGEDIR);   // compiled-in directory from Makefile
  53.  
  54.    char pagedir_names[MAXSTRING];   // Read in environment variable.
  55.    char *environment_variable;
  56.    if((environment_variable = getenv("LAMETEX_PS_PATH")) != NULL)
  57.       strcpy(pagedir_names, environment_variable);
  58.  
  59.    // Get all the pagedir paths from the environment variable.
  60.    char *start = pagedir_names;
  61.    char *p = strstr(start,":");
  62.    while(p) {
  63.       (*p) = '\0';
  64.       add_pagedir(start);
  65.       start = p+1;
  66.       p = strstr(start,":");
  67.    }
  68.    add_pagedir(start);
  69.  
  70.    for(int arg=1; arg<argc; arg++) {
  71.       if(argv[arg][0] == '-') {
  72.         switch (argv[arg][1]) {
  73.          case 'd':
  74.          case 'D':
  75.            add_pagedir(argv[++arg]);
  76.          case 'p':
  77.          case 'P':
  78.            strcpy(pspage,argv[++arg]);    // -p gives default pspage
  79.            break;
  80.              case 't':
  81.              case 'T':
  82.                plain_text_output = 1;
  83.            break;
  84.          default:
  85.            usage ();
  86.         }
  87.       }
  88.       else
  89.      strcpy(filename,argv[arg]);
  90.    }
  91.  
  92.    if(!filename[0]) {
  93.       cerr << "No files given to process." << endl;
  94.       exit(0);
  95.    }
  96.  
  97.    filenum = 0;
  98.  
  99.    if(!pspage[0])       // The default page template
  100.       strcpy(pspage,"page_latex.ps");
  101.  
  102.    /* Parse input file name to get output file name */
  103.    strcpy(outfileroot,filename);
  104.    p = strstr(outfileroot,".");
  105.    if(p)
  106.       (*p)='\0';
  107.    p = strrchr(outfileroot,'/');
  108.    if(p)
  109.       sprintf(outfilename,"%s.PS",p+1);
  110.    else
  111.       sprintf(outfilename,"%s.PS",outfileroot);
  112.  
  113.    /* Open files for reading and writing */
  114.    file[0] = new TextFile(filename);
  115.    cerr << "Opening " << outfilename << " for temporary output..." << endl;
  116.    outfile.open(outfilename);
  117. }
  118.  
  119. // Gets a new token from a list of files. If impossible, marks token invalid.
  120. void FileInput::get_token(Token &token)
  121. {
  122.    while(!token.isvalid()) {
  123.       if(!file[filenum]->isvalid()) {
  124.      delete file[filenum];
  125.      if(filenum == 0)       /* Done processing the original file */
  126.         return;
  127.      filenum--;             /* Pop up to parent file */
  128.       }
  129.       file[filenum]->get_token(token);
  130.    }
  131. }
  132.  
  133. // Include a file at this point in the flow
  134. void FileInput::include_file(char *filename)
  135. {
  136.    /* Has this include file been opened before? */
  137.    for(int x=0; x <= filenum; x++)
  138.       if(file[filenum]->match(filename)) {
  139.      char message[MAXSTRING];
  140.      sprintf(message, "Circular include loop while including file %s",
  141.          filename);
  142.       fatal_error(message);
  143.    }
  144.  
  145.    /* Are there too many files currently being processed? */
  146.    if(filenum >= MAXFILES-1) {
  147.      char message[MAXSTRING];
  148.      sprintf(message, "Too much include file nesting while including %s",
  149.          filename);
  150.       fatal_error(message);
  151.    }
  152.  
  153.    file[++filenum] = new TextFile(filename);
  154. }
  155.  
  156. // Prints an error message giving the current file and linenumber, and exits
  157. void FileInput::fatal_error(char *errormsg)
  158. {
  159.    file[filenum]->fatal_error(errormsg);
  160. }
  161.  
  162. // Prints a warning message giving the current file and linenumber
  163. void FileInput::warning(char *errormsg)
  164. {
  165.    file[filenum]->warning(errormsg);
  166. }
  167.  
  168. void FileInput::comma_delimiter(int value)
  169. {
  170.    comma_delimiter_valid = value;
  171. }
  172.  
  173. void FileInput::set_parsing_length(int value)
  174. {
  175.    parsing_length = value;
  176. }
  177.  
  178. void FileInput::add_pagedir(char *dirname)
  179. {
  180.    pagedir[num_pagedirs] = new char [ strlen(dirname) + 1 ];
  181.    strcpy(pagedir[num_pagedirs], dirname);
  182.  
  183.   // Take off a trailing '/' if needed
  184.    int length = strlen(pagedir[num_pagedirs]) -1;
  185.    if(pagedir[num_pagedirs][length] == '/')
  186.       pagedir[num_pagedirs][length] = '\0';
  187.  
  188.    num_pagedirs++;
  189. }
  190.  
  191. void FileInput::use_pspage(char *psname)
  192. {
  193.    strcpy(pspage, psname);
  194. }
  195.  
  196. // Force any pending vertical space or newlines to be printed
  197. void FileInput::force_space()
  198. {
  199.    float parindent;
  200.    if(Global::files->newline_in_this_blankline_area > 0) {
  201.       // If this is a new section, don't indent the first line
  202.       if(Global::stack->get(Environment::PDocument,
  203.                 Document::JustDidSection,"")) {
  204.      parindent = Global::stack->get(Environment::PLength,
  205.                     Length::Parameter, "\\parindent");
  206.      Global::stack->set(Environment::PLength, Length::Parameter, 0.0,
  207.                 "\\parindent");
  208.       }
  209.  
  210.       if(Global::files->vspace_in_this_blankline_area > 0.0)
  211.      Global::files->outfile << endl << "/vspace "
  212.         << Global::files->vspace_in_this_blankline_area
  213.         << " def NEWPARA" << endl;
  214.       else
  215.      Global::files->outfile << endl << "NEWPARA" << endl; 
  216.         
  217.  
  218.       if(Global::stack->get(Environment::PDocument,
  219.                 Document::JustDidSection,""))
  220.      Global::stack->set(Environment::PLength, Length::Parameter,
  221.                 parindent, "\\parindent");
  222.       
  223.       Global::files->readjust_vspace = 0.0;
  224.    }
  225.    Global::files->blankline_area = 0;
  226.    Global::files->newline_in_this_blankline_area = 0; 
  227.    Global::files->vspace_in_this_blankline_area = 0.0;
  228. }
  229.  
  230. // Check to see if a page has been started, and if not, start one.
  231. void FileInput::force_start_page()
  232. {
  233.    // Load new page description (if one has been defined)
  234.    include_file_ps(pspage, TRUE); 
  235.    
  236.    // Start new page?
  237.    if(!Stack::get(Environment::PDocument, Document::StartPage, "")) {
  238.       outfile << endl;
  239.       outfile << "STARTPAGE" << endl;
  240.       Stack::set(Environment::PDocument, Document::StartPage, 1.0, "");
  241.       blankline_area = 1;  // Suppress any new paragraphs
  242.       newline_in_this_blankline_area = 0;
  243.       vspace_in_this_blankline_area = 0.0;
  244.       Global::files->readjust_vspace = 0.0;
  245.    } else
  246.       force_space();
  247.  
  248.    // Force a pending Font command to be executed, if there is one.
  249.    Stack::set(Environment::PFont, Font::Pending, 0.0, "");
  250. }
  251.  
  252. /* Includes a postscript file in the current output stream. Handles
  253.  * page definitions properly if it is being asked to load a postscript
  254.  * file that is a page definition.
  255.  */
  256. void FileInput::include_file_ps(char *filename, int page_definition)
  257. {
  258.    if(!filename[0] || plain_text_output)
  259.       return;
  260.  
  261.    if(page_definition)
  262.       if(strcmp(filename, Global::files->current_pspage)==0) {
  263.      pspage[0] = '\0';
  264.      return;
  265.       }
  266.       else
  267.      strcpy(current_pspage, pspage);
  268.  
  269.    // First, end the current "formatdict" dictionary on top of the stack
  270.    outfile << endl << "end" << endl;
  271.  
  272.  
  273.    // Convert the given filename into a full path filename
  274.    char full_filename[MAXSTRING];   // Get the full pagename path.
  275.    class stat fileinfo;
  276.    int x;
  277.    
  278.    if(strstr(filename,"/")) {    //  Does this have any directories specified?
  279.       if(full_filename[0]=='/')
  280.      strcpy(full_filename, filename);
  281.       else
  282.      sprintf(full_filename, "./%s", filename);
  283.    } else {   // Look for the file in the all given PostScript directories
  284.       for(x=0; x < num_pagedirs; x++) {
  285.          sprintf(full_filename, "%s/%s", pagedir[x], filename);
  286.          if(stat(full_filename,&fileinfo)==0)     // Does this file exist?
  287.            break;
  288.       }
  289.       
  290.       if(x >= num_pagedirs) {  // Did not find postscript file
  291.      char message[MAXSTRING];
  292.      sprintf(message, "Cannot find PostScript file %s using path",
  293.          filename);
  294.      fatal_error(message);
  295.       }
  296.    }
  297.    
  298.    // Open the file for reading
  299.    cerr << "Including PostScript file " << full_filename << endl;
  300.    ifstream psfile(full_filename);
  301.    if(!psfile) {           // Open file failed?
  302.       cerr << "Unable to open postscript file " << full_filename << endl;
  303.       exit (-1);
  304.    }
  305.    
  306.    // Include the PostScript file in the current output
  307.    char psline[MAXSTRING];
  308.    
  309.    psfile.getline(psline, MAXSTRING, '\n');
  310.    while(!psfile.eof() && !psfile.fail()) {
  311.       outfile << psline << endl;
  312.       psfile.getline(psline, MAXSTRING, '\n');
  313.    }
  314.    
  315.    if(page_definition)
  316.       pspage[0] = '\0';
  317.  
  318.    // Now, start the current "formatdict" dictionary again
  319.    outfile << "formatdict begin" << endl;
  320. }
  321.  
  322. void FileInput::got_whitespace()
  323. {
  324.    file[filenum]->got_whitespace();
  325. }
  326.  
  327. int FileInput::whitespace_next()
  328. {
  329.    return file[filenum]->whitespace_next();
  330. }
  331.  
  332. int FileInput::whitespace_prev()
  333. {
  334.    return file[filenum]->whitespace_prev();
  335. }
  336.  
  337. TextFile::TextFile(char *name)
  338. {
  339.    if(!name) {
  340.       valid = FALSE;
  341.       return;
  342.    }
  343.  
  344.    char *p = strstr(name,".");
  345.    if(!p)
  346.       sprintf(filename,"%s.tex",name);
  347.    else
  348.       strcpy(filename,name);
  349.    current_file.open(filename);
  350.    if(!current_file) {           // Open file failed?
  351.       cerr << "Unable to open LaTeX file " << filename << endl;
  352.       exit (-1);
  353.    }
  354.  
  355.    cerr << "Processing " << filename << "..." << endl;
  356.  
  357.    linenum=1;
  358.    token_on_this_line = FALSE;
  359.    just_got_a_newline = FALSE;
  360.    just_got_whitespace = TRUE;
  361.    previous_got_whitespace = TRUE;
  362.    parsing_command = FALSE;
  363.    valid = TRUE;
  364. }
  365.  
  366. TextFile::~TextFile()
  367. {
  368.    current_file.close();
  369. }
  370.  
  371. /* Gets a new token from a file.
  372.  *    If impossible, leaves token marked "invalid".
  373.  */
  374. void TextFile::get_token(Token& token)
  375. {
  376.    char ch;
  377.  
  378.    // We want to set these two flags for every newline, but only
  379.    // after the token flagged by the newline has been processed!
  380.  
  381.    if(just_got_a_newline) {
  382.       Stack::set(Environment::PDocument, Document::Comment, 0.0, "");
  383.       linenum++;
  384.       just_got_a_newline = FALSE;
  385.    }
  386.  
  387.    if(!isvalid())
  388.       return;
  389.  
  390.    /* If we're in a postscript environment, dump postscript 'til it closes */
  391.    if(Global::stack->get(Environment::PDocument, Document::PostScript, "")) {
  392.       Global::files->force_start_page();  // Start a new page if not started.
  393.       char commentline[MAXSTRING];
  394.       char *end;
  395.       int x, stop, comments;
  396.       comments=0;
  397.       do {
  398.      for(x=0, stop=FALSE; x < MAXSTRING && !stop; x++) {
  399.         current_file.get(ch);
  400.         switch(ch) {
  401.         case '\n':
  402.            comments=0;
  403.            just_got_a_newline = TRUE;
  404.            linenum++;
  405.            commentline[x] = '\0';
  406.            stop = TRUE;
  407.            break;
  408.         case ' ':
  409.            just_got_a_newline = FALSE;
  410.            commentline[x] = '\0';
  411.            stop = TRUE;
  412.            break;
  413.         default:
  414.            just_got_a_newline = FALSE;
  415.            commentline[x] = ch;
  416.            break;
  417.         }
  418.      }
  419.          
  420.      end = strstr(commentline,"\\end{postscript}");
  421.      if(end) {
  422.         (*end) = '\0';
  423.      }
  424.      if(commentline[0] == '%' && !comments) {
  425.         Global::files->outfile << &commentline[1];  // Skip initial '%'
  426.         comments++;
  427.      }
  428.      else
  429.         Global::files->outfile << commentline;
  430.      Global::files->outfile << (char) ch;
  431.       }
  432.       while(!end && !current_file.eof() && !current_file.fail());
  433.       Stack::pop(0, Document::End, 0.0, "\\postscript");
  434.    }
  435.  
  436.    /* If we're in a verbatim environment, dump text 'til it closes */
  437.    if(Global::stack->get(Environment::PDocument, Document::Verbatim, "")) {
  438.       Global::files->force_start_page();  // Start a new page if not started.
  439.       Global::files->outfile << " NEWPARA" << endl;
  440.       char commentline[MAXSTRING];
  441.       char *end;
  442.       do {
  443.        current_file.getline(commentline, MAXSTRING, '\n');
  444.        just_got_a_newline = TRUE;
  445.        linenum++;
  446.        
  447.        end = strstr(commentline,"\\end{verbatim}");
  448.  
  449.        if(end) {
  450.         (*end) = '\0';
  451.        }
  452.        char output[MAXSTRING];
  453.        Operator::registrar(commentline, output);
  454.        Global::files->outfile << output << " VERBATIM" << endl;
  455.       }
  456.       while(!end && !current_file.eof() && !current_file.fail());
  457.       Stack::pop(0, Document::End, 0.0, "\\verbatim");
  458.    }
  459.  
  460.    /* If we're in an ignore environment, do nothing 'til it closes */
  461.    if(Global::stack->get(Environment::PDocument, Document::Ignore, "")) {
  462.       char commentline[MAXSTRING];
  463.       char *end;
  464.       int x, stop, comments;
  465.       comments=0;
  466.       do {
  467.      for(x=0, stop=FALSE; x < MAXSTRING && !stop; x++) {
  468.         current_file.get(ch);
  469.         switch(ch) {
  470.         case '\n':
  471.            comments=0;
  472.            just_got_a_newline = TRUE;
  473.            linenum++;
  474.            commentline[x] = '\0';
  475.            stop = TRUE;
  476.            break;
  477.         case ' ':
  478.            just_got_a_newline = FALSE;
  479.            commentline[x] = '\0';
  480.            stop = TRUE;
  481.            break;
  482.         default:
  483.            just_got_a_newline = FALSE;
  484.            commentline[x] = ch;
  485.            break;
  486.         }
  487.      }
  488.          
  489.      end = strstr(commentline,"\\end{ignore}");
  490.       }
  491.       while(!end && !current_file.eof() && !current_file.fail());
  492.       Stack::pop(0, Document::End, 0.0, "\\ignore");
  493.    }
  494.  
  495.    int pos = 0;
  496.    int token_started = FALSE;
  497.    int in_a_number = FALSE;
  498.    previous_got_whitespace = just_got_whitespace;
  499.  
  500.    // Loop through characters in the file unless some file error occurs.
  501.    for(current_file.get(ch); ch && !current_file.eof() && !current_file.fail();
  502.        current_file.get(ch)){
  503.       if(just_got_a_newline) {
  504.      Stack::set(Environment::PDocument, Document::Comment, 0.0, "");
  505.      linenum++;
  506.      just_got_a_newline = FALSE;
  507.       }
  508.  
  509.       switch(ch) {
  510.       case '\\':
  511.       case '{':
  512.       case '}':
  513.       case '[':
  514.       case ']':
  515.      break;
  516.       default:
  517.      if(!parsing_command && ch != '\\')
  518.         just_got_whitespace = isspace(ch);
  519.      break;
  520.       }
  521.       switch(ch) {                         // What is the character?
  522.       case '%':                            // The special comment character
  523.      if(token_started) {         // If currently inside a token, it's
  524.         current_file.putback(ch);
  525.         token_text[pos++] = '\0'; // interpreted as an end-token
  526.         token.make_text(token_text);   // Successfully got a token.
  527.         return;
  528.      } else
  529.         Stack::set(Environment::PDocument, Document::Comment, 1.0, "");
  530.      break;
  531.       case '\n':
  532.      just_got_a_newline = TRUE;
  533.          // End a \STEALTH with a newline
  534.      if(Stack::get(Environment::PDocument, Document::Stealth, "")==2.0)
  535.         Stack::set(Environment::PDocument, Document::Stealth, 0.0, "");
  536.  
  537.      if(!token_on_this_line) {   // Is this text line entirely whitespace
  538.         token_text[0] = '\0';    // If so, return the blank line token "".
  539.         token.make_text(token_text);
  540.         return;
  541.      }
  542.      token_on_this_line = FALSE;
  543.       case ' ':
  544.       case '\t':
  545.      if(token_started) {               // Marks back or front of token?
  546.         token_text[pos++] = '\0';
  547.         token.make_text(token_text);   // Successfully got a token.
  548.         return;
  549.      }
  550.          parsing_command = FALSE;
  551.      break;
  552.       case '{':
  553.       case '[':
  554.       case '}':
  555.       case ']':
  556.      token_on_this_line = TRUE;
  557.      if(token_started)                 // Marks back or front of token?
  558.             if(pos==1 && token_text[0] == '\\') // Is the token "\{" or "\{" ?
  559.                token_text[pos++] = ch;
  560.             else { // We must do look-ahead to set just_got_whitespace.
  561.                    // What is the first character after the '}' character(s)?
  562.                current_file.putback(ch);
  563.             }
  564.      else {
  565.         token_text[pos++] = ch;
  566.             if(ch == '}' && !parsing_command) {
  567.                for(int x=0; ch == '}'; x++)
  568.                    current_file.get(ch);
  569.                just_got_whitespace = isspace(ch);
  570.                current_file.putback(ch);
  571.  
  572.                for(int y=0; y < x-1; y++)
  573.                   current_file.putback('}');
  574.             }
  575.          }
  576.          parsing_command = FALSE;
  577.      token_text[pos++] = '\0';
  578.      token.make_text(token_text);      // Successfully got a token.
  579.      return;
  580.       case '\\':
  581.      parsing_command = TRUE;
  582.          if(token_started) {
  583.             current_file.putback(ch);
  584.           token_text[pos++] = '\0';
  585.         token.make_text(token_text);   // Successfully got a token.
  586.         return;
  587.          }
  588.          token_started = TRUE;
  589.          token_text[pos++] = ch;
  590.          current_file.get(ch);   // Look for special 2 character commands.
  591.          switch(ch) {
  592.          case '\\':
  593.          case '&':
  594.          case '%':
  595.          case '#':
  596.          case '{':
  597.          case '}':
  598.          case '_':
  599.             token_text[pos++] = ch;
  600.           token_text[pos++] = '\0';
  601.         token.make_text(token_text);   // Successfully got a token.
  602.             current_file.get(ch);
  603.         just_got_whitespace = isspace(ch);
  604.             current_file.putback(ch);
  605.         return;
  606.          default:
  607.             current_file.putback(ch);
  608.             break;
  609.          }
  610.          break;
  611.       case ',':
  612.          if(comma_delimiter_valid && token_started) {
  613.         token_text[pos++] = '\0';
  614.         token.make_text(token_text);   // Successfully got a token.
  615.         return;
  616.      }
  617.       case '0': case '1': case '2': case '3': case '4': case '5': case '6':
  618.       case '7': case '8': case '9': case '.': case '-':
  619.          if(parsing_length && token_started && !in_a_number) {
  620.         token_text[pos++] = '\0';
  621.         token.make_text(token_text);   // Successfully got a token.
  622.         current_file.putback(ch);
  623.         return;
  624.          }
  625.          in_a_number = TRUE;
  626.      token_on_this_line = TRUE;
  627.      if(!token_started)
  628.         token_started = TRUE;
  629.      if(pos < MAXSTRING - 1)
  630.         token_text[pos++] = ch;
  631.      else {
  632.         cerr << "File contains words that are longer than "
  633.          << MAXSTRING << " characters!" << endl;
  634.         exit(-1);
  635.      }
  636.      break;
  637.      // These are characters we want to skip, but they can define
  638.      // the ends of tokens.
  639.     case '$': case '#': case '~': case '&': case '^':
  640.  
  641.          if(token_started) {
  642.           token_text[pos++] = '\0';
  643.         token.make_text(token_text);   // Successfully got a token.
  644.         parsing_command = FALSE;
  645.         return;
  646.          }
  647.          break;
  648.       case ':': case ';': case '?': case '!': case '`': case '_':
  649.       case '\'': case '(': case ')': case '/': case '*': case '@':
  650.       case '+': case '=': case '|': case '<': case '>': case '"':
  651.      parsing_command = FALSE;
  652.       case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'G':
  653.       case 'H': case 'I': case 'J': case 'K': case 'L': case 'M': case 'N':
  654.       case 'O': case 'P': case 'Q': case 'R': case 'S': case 'T': case 'U':
  655.       case 'V': case 'W': case 'X': case 'Y': case 'Z':
  656.       case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'g':
  657.       case 'h': case 'i': case 'j': case 'k': case 'l': case 'm': case 'n':
  658.       case 'o': case 'p': case 'q': case 'r': case 's': case 't': case 'u':
  659.       case 'v': case 'w': case 'x': case 'y': case 'z':
  660.          if(parsing_length && token_started && in_a_number) {
  661.         token_text[pos++] = '\0';
  662.         token.make_text(token_text);   // Successfully got a token.
  663.         current_file.putback(ch);
  664.         return;
  665.          }
  666.      token_on_this_line = TRUE;
  667.      if(!token_started)
  668.         token_started = TRUE;
  669.      if(pos < MAXSTRING - 1)
  670.         token_text[pos++] = ch;
  671.      else {
  672.         cerr << "File contains words that are longer than "
  673.          << MAXSTRING << " characters!" << endl;
  674.         exit(-1);
  675.      }
  676.      break;
  677.       default:
  678.      cerr << "File contains illegal character " << (int) ch << endl;
  679.      exit(-1);
  680.      break;
  681.       }
  682.    }
  683.    valid = FALSE;                          // Reached END OF FILE
  684.    if(token_started) {
  685.       token_text[pos++] = '\0';
  686.       token.make_text(token_text);   // Successfully got a token.
  687.    }
  688. }
  689.  
  690. int TextFile::isvalid()
  691. {
  692.    return(valid);
  693. }
  694.  
  695. int TextFile::match(char *name)
  696. {
  697.    return(!strcmp(name, filename));
  698. }
  699.  
  700. void TextFile::fatal_error(char *errormsg)
  701. {
  702.    cerr << "\"" << filename 
  703.     << "\", line " << linenum
  704.     << ": error at \"" << token_text
  705.     << "\":  " << errormsg << endl;
  706.    exit(-1);
  707. }
  708.  
  709. void TextFile::warning(char *errormsg)
  710. {
  711.    cerr << "\"" << filename 
  712.     << "\", line " << linenum
  713.     << ": warning at \"" << token_text
  714.     << "\":  " << errormsg << endl;
  715. }
  716.  
  717. void TextFile::got_whitespace()
  718. {
  719.    just_got_whitespace = 1;
  720. }
  721.  
  722. int TextFile::whitespace_next()
  723. {
  724.    return just_got_whitespace;
  725. }
  726.  
  727. int TextFile::whitespace_prev()
  728. {
  729.    return previous_got_whitespace;
  730. }
  731.